/*
 * =====================================================================================
 *
 *       Filename:  redis_cluster.cpp
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  03/16/2018 01:22:09 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *   Organization:  
 *
 * =====================================================================================
 */
#include <iostream>
#include "redis_cluster.h"
#include "slothash.h"

using namespace std;

RedisCluster* RedisCluster::m_instance = NULL;
RedisCluster* RedisCluster::instance()
{
    if (m_instance != NULL)
        return m_instance;

    m_instance = new RedisCluster();
    return m_instance;
}

RedisCluster::~RedisCluster()
{
	clear();
}

void RedisCluster::clear()
{
	m_nodes.clear();
    map<ClusterNode,RedisConn*>::iterator it = m_conns.begin();
	for( ; it != m_conns.end(); ++it)
	{
		delete it->second;
	}
	m_conns.clear();
}

void RedisCluster::release()
{
    delete m_instance;
    m_instance = NULL;
}


bool RedisCluster::loadSlots(const vector<ClusterNode>& nodes,const struct timeval& tmout)
{
    vector<ClusterNode>::const_iterator it;
    for (it = nodes.begin(); it != nodes.end(); ++it)
    {
        // 能过一个节点就可以获取到集群的所有信息了
		RedisConn conn(it->m_ip,it->m_port,tmout);
		if (conn.loadClusterSlots(tmout))
			return true;
    }

    return false;
}

bool RedisCluster::reloadSlots()
{
	map<ClusterNode,RedisConn*>::iterator it;
	bool bsucc = false;
	for (it = m_conns.begin(); it != m_conns.end(); ++it)
	{
		if (it->second != NULL 
			&& !it->second->connected()
			&& !it->second->connect()
			)
			continue;

		if (it->second->loadClusterSlots(it->second->m_tmout))
		{
			bsucc = true;
			break;
		}
	}
	cout<<"reload:"<<bsucc<<endl;
	return bsucc;
}

RedisConn* RedisCluster::getConn(const string& key)
{
    if (m_conns.empty())
        return NULL;
	unsigned int slot = HashSlot::slot(key.c_str(),key.length());
	map<SlotRange,vector<ClusterNode> >::iterator itN;
	map<ClusterNode,RedisConn*>::iterator itC;
	for (itN = m_nodes.begin(); itN != m_nodes.end(); ++itN)
	{
		if ( slot < itN->first.m_min || slot > itN->first.m_max)
			continue;
		
		vector<ClusterNode>::iterator itMaster;
		for (itMaster = itN->second.begin(); 
			itMaster != itN->second.end(); 
			++itMaster)
		{
			itC = m_conns.find(*itMaster);
			if (itC != m_conns.end() 
				&& (itC->second != NULL)
				&& ( itC->second->connected() 
					|| itC->second->connect())
			)
			{
				return itC->second;
			}
		}
	}

	return NULL;
}

RedisConn* RedisCluster::getConn(const ClusterNode& node)
{
	map<ClusterNode,RedisConn*>::iterator it = m_conns.find(node);
	if (it == m_conns.end())
		return NULL;
	
	return it->second;
}

RedisConn* RedisCluster::getConn(const string& ip,unsigned int port)
{
	ClusterNode node(ip,port);
	map<ClusterNode,RedisConn*>::iterator it = m_conns.find(node);
	if (it == m_conns.end())
		return NULL;
	
	return it->second;
}
	










